package com.xlh.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.xlh.common.Result;
import com.xlh.constant.UserConstant;
import com.xlh.dto.user.LocalStorageDTO;
import com.xlh.enums.LocalResourcesEnum;
import com.xlh.enums.SystemConfigEnum;
import com.xlh.enums.user.EventCodeEnum;
import com.xlh.enums.user.RoleEnum;
import com.xlh.listener.OperationLoginListener;
import com.xlh.listener.OperationLoginTask;
import com.xlh.pojo.system.Operation;
import com.xlh.pojo.user.User;
import com.xlh.service.system.OperationService;
import com.xlh.service.system.SystemConfigService;
import com.xlh.service.user.UserService;
import com.xlh.util.RequestUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Set;

/**
 * 登录成功时，自定义的返回结果
 *
 * @author cheer
 */
@Component
public class RestAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private OperationService operationService;

    @Autowired
    private UserService userService;

    @Value("${project.internet}")
    private Boolean recorded;

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException {

        // 获取用户信息放到结果集中
        LocalStorageDTO localStorageDTO = getUserInfo();

        // 将logo配置文件放置到结果集中
        localStorageDTO.setConfig(
                systemConfigService.listConfigByKey(
                        Lists.newArrayList(SystemConfigEnum.INNER_LOGO_IMAGE.getKey(),
                                SystemConfigEnum.PROJECT_NAME.getKey())
                )
        );

        // 将验证码放置session中
        HttpSession session = request.getSession(true);
        String tel = (String) session.getAttribute(UserConstant.MOBILE_TEL_SESSION_KEY);
        session.removeAttribute(UserConstant.CODE_SESSION_KEY);
        session.removeAttribute(UserConstant.CODE_FAIL_NUM);
        session.removeAttribute(UserConstant.SMS_CODE_SESSION_KEY);
        session.removeAttribute(UserConstant.MOBILE_TEL_SESSION_KEY);
        session.removeAttribute(UserConstant.SMS_SEND_FAIL_SESSION_KEY);

        String ip = RequestUtil.getIpAddress(request);
        Operation operation = operationService.insertOpertion(ip, EventCodeEnum.LOGIN, null);

        if (recorded) {
            // 异步执行登陆获取信息
            OperationLoginListener.getDelayQueue().put(
                    new OperationLoginTask(operation.getOperationExtendId(), 1));

            // 当用户需要输入短信验证码时，就修改ip
            if (StringUtils.isNotBlank(tel)) {
                updateUserIp(ip);
            }
        }

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(objectMapper.writeValueAsString(Result.success(localStorageDTO)));
        response.getWriter().flush();
    }

    private LocalStorageDTO getUserInfo() {
        // 在结果集中配置用户信息 及 logo等信息，使得前端放到本地缓存中。
        User user = userInfoHolder.getUser();
        LocalStorageDTO localStorageDTO = new LocalStorageDTO();
        localStorageDTO.setName(user.getName());
        localStorageDTO.setRoleCode(RoleEnum.codeToName(user.getRole()));
        localStorageDTO.setIcon(LocalResourcesEnum.SYSTEM_FILE.getMappingUrl(user.getIcon()));
        localStorageDTO.setUserNumber(user.getUserNumber());
        localStorageDTO.setIsAdmin(userInfoHolder.isAdmin());
        localStorageDTO.setIsStudent(userInfoHolder.isStudent());
        localStorageDTO.setIsTeacher(userInfoHolder.isTeacher());
        return localStorageDTO;
    }

    private void updateUserIp(String ip){
        User user = new User();
        Set<String> dbIps = StringUtils.isBlank(userInfoHolder.getUser().getIp()) ?
                Sets.newHashSet() : Sets.newHashSet(userInfoHolder.getUser().getIp().split(","));
        int dbIpCount = dbIps.size();
        if (dbIps.size() >= UserConstant.COMMON_IP_COUNT) return;

        dbIps.add(ip);
        if (Objects.equal(dbIps.size(), dbIpCount)) return;

        user.setIp(String.join(",", dbIps));
        userService.updateUserSelective(userInfoHolder.getUser().getId(), user);
    }

}
